/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.oea.hibernate.entities;

import com.oea.hibernate.utilities.HibernateUtil;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.Query;
import org.hibernate.Session;

/**
 *
 * @author User
 */
@Table(name = "schedules")
@Entity
public class Schedule extends AbstractEntity {

    @Id
    @Column(name = "id")
    @GeneratedValue
    protected Long id;

    @Column(name = "fid")
    private Long fid;

    @Transient
    protected Faculty faculty;

    public Faculty getFaculty() {
        return faculty;
    }

    public void setFaculty() {
        this.faculty = (Faculty) new Faculty().getById(this.fid);
    }

    @Column(name = "divid")
    private Long divid;

    @Transient
    protected Division division;

    public Division getDivision() {
        return division;
    }

    public void setDivision() {
        this.division = (Division) new Division().getById(this.divid);
    }

    @Column(name = "subid")
    protected Long subid;

    @Transient
    protected Subject subject;

    public Subject getSubject() {
        return subject;
    }

    public void setSubject() {
        this.subject = (Subject) new Subject().getById(subid);
    }

    @Column(name = "currentday")
    protected int day;

    @Column(name = "lecno")
    protected int lecno;

    @Column(name = "type")
    protected boolean type;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getFid() {
        return fid;
    }

    public void setFid(Long fid) {
        this.fid = fid;
    }

    public Long getDivid() {
        return divid;
    }

    public void setDivid(Long divid) {
        this.divid = divid;
    }

    public Long getSubid() {
        return subid;
    }

    public void setSubid(Long subid) {
        this.subid = subid;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getLecno() {
        return lecno;
    }

    public void setLecno(int lecno) {
        this.lecno = lecno;
    }

    public boolean isType() {
        return type;
    }

    public void setType(boolean type) {
        this.type = type;
    }

    public static List<List<Schedule>> getTimeTableForDivision(Long division,  Parameter parameters, List<Faculty_Subject> allsubjects) {
        List<List<Schedule>> days = new ArrayList<>();

        // all logic
        for (int i = 0; i < parameters.getDaysperweek(); i++) {
            List<Schedule> day = new ArrayList<>();

            for (int j = 0; j < parameters.getLecturesperday(); j++) {
                Schedule lecture = Schedule.getSchedule(day, days, allsubjects, i, j);
                lecture.setDivid(division);

//                if (lecture.isType()) {
//                    day.add(lecture);
//                } else {
//                    day.add(lecture);
//                    day.add(lecture);
//                    j++;
//                }
                //for labslot
                if (j != (parameters.getLabslot() - 1) && lecture.isType()) {
                    day.add(lecture);
                } else if (j != (parameters.getLabslot() - 1)) {
                    lecture.setType(true);
                    day.add(lecture);
                } else if (j == (parameters.getLabslot() - 1) && !lecture.isType()) {
                    day.add(lecture);
                    day.add(lecture);
                    j++;
                } else if (j == (parameters.getLabslot() - 1)) {
                    lecture.setType(false);
                    day.add(lecture);
                    day.add(lecture);
                    j++;
                }
            }
            days.add(day);
        }
        System.out.println(days);
        return days;
    }

    public static Schedule getSchedule(List<Schedule> day, List<List<Schedule>> days, List<Faculty_Subject> allsubjects, int which_day, int which_slot) {

        long subid = 0l;
        Faculty_Subject bs;

        Schedule schedule = new Schedule();

        List<Faculty_Subject> temp = new ArrayList<>();
        temp.addAll(allsubjects);

        // check if that subject is already alloted on that day
        for (int j = 0; j < day.size(); j++) {
            System.out.println("Checking subject  =" + day.get(j).getSubid());
            removeFromTemp(day.get(j).getSubid(), temp);
        }

        // check if subject load complete for week
        List<Faculty_Subject> to_be_removed = new ArrayList<>();
        System.out.println("Checking temp =" + temp.size());

        for (Faculty_Subject bsu : temp) {
            if (bsu.getSubject().getLecturesperweek() == 0 && bsu.getSubject().getLabsperweek() == 0) {
                to_be_removed.add(bsu);
            }
            if (bsu.getSubject().getLabsperweek() == 0) {

                bsu.getSubject().setType(true);
            }
            if (bsu.getSubject().getLecturesperweek() == 0) {
                bsu.getSubject().setType(false);
            }
        }
        temp.removeAll(to_be_removed);

        to_be_removed.clear();

        // check if all faculties taking those subjects are busy elsewhere or not
        for (Faculty_Subject fs : temp) {
            List<Schedule> lectures_for_faculty = Schedule.getSchedulesByFaculty(fs.getFid());
            for (Schedule sc : lectures_for_faculty) {
                //get this lecture slot
                // get this lecture day
                if (which_day == sc.getDay() && which_slot == sc.getLecno()) {
                    to_be_removed.add(fs);
                }
            }
        }

        temp.removeAll(to_be_removed);

        to_be_removed.clear();

        for (Faculty_Subject fs : temp) {
            List<Faculty_Subject> faculty_subject = Faculty_Subject.getSubjectsOfFaculty(fs.getFid());
            for (Faculty_Subject fas : faculty_subject) {
                //--- for faculty load checking

                if (fas.getNooflectures() == 0 && fas.getNooflabs() == 0) {
                    to_be_removed.add(fas);
                }
                if (fas.getNooflabs() == 0) {
                    if (fas.getSubject() != null) {
                        fas.getSubject().setType(true);
                    }
                }
                if (fas.getNooflectures() == 0) {
                    if (fas.getSubject() != null) {

                        fas.getSubject().setType(false);
                    }
                }
            }
        }

        temp.removeAll(to_be_removed);

        to_be_removed.clear();

        if (temp.size() > 0) {
            System.out.println("Checking temp =" + temp.size());
            bs = temp.get(0);
        } else {

            bs = allsubjects.get(0);// or randomize it
        }

        if (bs.getSubject().isType() == false) {
            bs.getSubject().setLabsperweek(bs.getSubject().getLabsperweek() - 1);
        }
        if (bs.getSubject().isType()== true) {
            bs.getSubject().setLecturesperweek(bs.getSubject().getLecturesperweek() - 1);
        }

        if (bs.getSubject().isType()== false) {
            bs.setNooflabs(bs.getNooflabs() - 1);
            System.out.println("no remaining lab for faclty" + bs.getFid() + bs.getNooflabs());
        }

        if (bs.getSubject().isType()== true) {
            bs.setNooflectures(bs.getNooflectures() - 1);
            System.out.println("no of remain lectures for faculty" + bs.getFid() + bs.getNooflectures());
        }

        schedule.setDay(which_day);
        schedule.setLecno(which_slot);
        schedule.setSubid(bs.getSubid());
        schedule.setFid(bs.getFid());
        schedule.setType((bs.getSubject().isType()));
//getType() == 1) ? true : false
        schedule.setFaculty();
        schedule.setSubject();

        return schedule;

    }

    //get labs slots per day
    //render lectures except slots of labs
    //rendering of subjects in labs
    // list<faculty_subjects> labs=new arraylist()
    //labs.addAll(subjects);
    //get number of batches(batch)
    //for each day
    //   for lab
    //      for all batches
    //          same as subjects assign labs in all batches
    //
    public static void removeFromTemp(long subid, List<Faculty_Subject> temp) {
        Faculty_Subject to_be_remmoved = null;
        for (Faculty_Subject bs : temp) {
            if (bs.getSubid().equals(subid)) {
                to_be_remmoved = bs;
                System.out.println("Removing Subject =" + to_be_remmoved.getSubid());
            }
        }
        temp.remove(to_be_remmoved);
    }

    public static List<Schedule> getSchedulesByFaculty(Long fid) {
        List<Schedule> list = null;

        Session s = HibernateUtil.getSessionFactory().openSession();
        Query q = s.createQuery("from Schedule where fid='" + fid + "'");

        list = (List<Schedule>) q.list();
        return list;
        // from Schedule where fid= '"+fid+"';

    }

    public static List<Schedule> getSchedulesFormDatabase(Long divid) {
        Schedule sc = new Schedule();
        List<Schedule> all_lecture = null;
        Session s = HibernateUtil.getSessionFactory().openSession();
        Query q = s.createQuery("from Schedule where divid='" + divid + "'");
        all_lecture = (List<Schedule>) q.list();
        return all_lecture;

    }

    public static List<Schedule> getSchedulesForFaculty(Long fid) {
        List<Schedule> all_lecture = null;
        Session s = HibernateUtil.getSessionFactory().openSession();
        Query q = s.createQuery("from Schedule where fid='" + fid + "'");
        all_lecture = (List<Schedule>) q.list();
        return all_lecture;
    }

    public static List<Schedule> getSchedulesForSlot(int day, int lecno) {
        List<Schedule> all_lecture = null;
        Session s = HibernateUtil.getSessionFactory().openSession();
        Query q = s.createQuery("from Schedule where day='" + day + "'and lecno='" + lecno + "'");
        all_lecture = (List<Schedule>) q.list();
        return all_lecture;
    }

}
